﻿#include "framework.h"
#include "GameBoard.h"

// 函数声明
static void GameBoard_Delete(GameBoard*);
static void GameBoard_OnPaint(GameBoard*);
static LRESULT CALLBACK GameBoard_Proc(HWND, UINT, WPARAM, LPARAM);

/**
 * 创建游戏区域。
 * @param parent    父窗口
 * @param x, y      左上角坐标
 * @param width     宽度
 * @param height    高度
 * @return 游戏区域
 */
GameBoard* New_GameBoard(HWND parent, int x, int y, int width, int height) {
    WNDCLASSEX wndClass = { sizeof(WNDCLASSEX) };
    GameBoard* gameBoard = (GameBoard*)calloc(1, sizeof(GameBoard));
    LPCTSTR name = _T("GameBoard");

    // 注册窗口类
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.lpfnWndProc = GameBoard_Proc;
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.lpszClassName = name;
    RegisterClassEx(&wndClass);

    // 初始化数据
    gameBoard->mHandle = CreateWindow(name, NULL, WS_CHILD | WS_VISIBLE, x, y, width, height, parent, NULL, NULL, NULL);
    SetWindowLongPtr(gameBoard->mHandle, GWLP_USERDATA, (LONG_PTR)gameBoard);
    gameBoard->mBitmap = CreateCompatibleBitmap(GetDC(gameBoard->mHandle), width, height);
    gameBoard->mDrawer = CreateCompatibleDC(GetDC(gameBoard->mHandle));
    SelectObject(gameBoard->mDrawer, gameBoard->mBitmap);
    gameBoard->mSize.cx = width;
    gameBoard->mSize.cy = height;

    // 初始化函数
    gameBoard->deleteSelf = GameBoard_Delete;

    return gameBoard;
}

/**
 * 删除游戏区域。
 * @param gameBoard 游戏区域
 */
static void GameBoard_Delete(GameBoard* gameBoard) {
    DeleteDC(gameBoard->mDrawer);
    DeleteObject(gameBoard->mBitmap);
    DestroyWindow(gameBoard->mHandle);
    free(gameBoard);
}

/**
 * 重绘事件的响应函数。
 * @param gameBoard 游戏区域
 */
static void GameBoard_OnPaint(GameBoard* gameBoard) {
    PAINTSTRUCT ps = { 0 };
    BeginPaint(gameBoard->mHandle, &ps);
    BitBlt(ps.hdc, 0, 0, gameBoard->mSize.cx, gameBoard->mSize.cy, gameBoard->mDrawer, 0, 0, SRCCOPY);
    EndPaint(gameBoard->mHandle, &ps);
}

/**
 * 窗口过程函数。
 * @param window    窗口
 * @param message   事件标识
 * @param wParam    事件相关信息
 * @param lParam    事件相关信息
 * @return 事件在此被处理则返回 TRUE，否则返回 FALSE
 */
static LRESULT CALLBACK GameBoard_Proc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) {
    GameBoard* gameBoard = (GameBoard*)GetWindowLongPtr(window, GWLP_USERDATA);
    switch (message) {
        case WM_LBUTTONUP:
            PostMessage(GetParent(window), message, wParam, lParam);
            break;
        case WM_PAINT:
            GameBoard_OnPaint(gameBoard);
            break;
    }
    return DefWindowProc(window, message, wParam, lParam);
}
